/*
 * serialport.c
 *
 *  Created on: 2021年2月19日
 *      Author: taoyu
 */

#include "serialport_settings.h"
#include "serialport.h"
#include "serialport_hooks.h"
#include "serialport_events.h"

typedef enum
{
	TX_STATE_INIT = 0,
	TX_STATE_IDLE,
	TX_STATE_BUSY,
}
TX_STATE;

typedef enum
{
	RX_STATE_INIT = 0,
	RX_STATE_IDLE,
	RX_STATE_BUSY,
	RX_STATE_READY,
	RX_STATE_OVERFLOW,
}
RX_STATE;

typedef struct
{
	// tx
	TX_STATE txState;
	uint8 txBuffer[SERIAL_PORT_BUFFER_SIZE];
	uint8 txLength;
	uint8 txCount;

	// rx
	RX_STATE rxState;
	uint8 rxBuffer[SERIAL_PORT_BUFFER_SIZE];
	uint8 rxCount;
	uint8 rxLength;
	uint8 rxOverflowCount;
}
SERIAL_PORT_DATA;

SERIAL_PORT_DATA	sp_Data[SERIAL_PORT_CHANNEL_MAX];

void serialport_init(SERIAL_PORT_CHANNEL channel)
{
	sp_Data[channel].txState = TX_STATE_IDLE;
	sp_Data[channel].rxState = RX_STATE_IDLE;
	sp_Data[channel].rxOverflowCount = 0;
}

void serialport_task(SERIAL_PORT_CHANNEL channel)
{

}

int serialport_sendPackage(SERIAL_PORT_CHANNEL channel, uint8 * pData, uint8 length)
{
	uint8 i;

	/* check arguments */
	if( channel>=SERIAL_PORT_CHANNEL_MAX ) return -1;
	if( !pData ) return -2;
	if( !length ) return -3;

	/* check data length and buffer size */
	if( length>sizeof(sp_Data[channel].txBuffer) ) return -4;

	/* check tx state */
	if( sp_Data[channel].txState != TX_STATE_IDLE ) return -5;

	/* copy data */
	for(i=0;i<length;i++) sp_Data[channel].txBuffer[i] = pData[i];
	sp_Data[channel].txLength = length;

	/* start send */
	sp_Data[channel].txCount = 0;
	sp_Data[channel].txState = TX_STATE_BUSY;
	serialportHook_startSend(channel);

	/* started */
	return length;
}

int serialportEvent_sendBufferEmpty_IRQ(SERIAL_PORT_CHANNEL channel)
{
	int ret = 0;

	// check state
	if( sp_Data[channel].txState == TX_STATE_BUSY )
	{
		// check end
		if( sp_Data[channel].txCount < sp_Data[channel].txLength )
		{
			// send the data
			serialportHook_sendData(channel, sp_Data[channel].txBuffer[sp_Data[channel].txCount]);
			// next
			sp_Data[channel].txCount ++;
		}
		else
		{
			ret = -2;
		}
	}
	else
	{
		ret = -1;
	}

	// if no next data, stop send, back to idle
	if( ret<0 )
	{
		serialportHook_stopSend(channel);
		sp_Data[channel].txState = TX_STATE_IDLE;
	}

	return ret;
}

int serialportEvent_dataByteReceived_IRQ(SERIAL_PORT_CHANNEL channel, uint8 data)
{
	int ret = 0;

	switch( sp_Data[channel].rxState )
	{
	case	RX_STATE_IDLE:
		// this is the first data
		sp_Data[channel].rxBuffer[0] = data;
		sp_Data[channel].rxCount = 1;
		// change state to busy
		sp_Data[channel].rxState = RX_STATE_BUSY;
		// reset overflow counter
		sp_Data[channel].rxOverflowCount = 0;
		break;
	case	RX_STATE_BUSY:
		// store the data
		if(sp_Data[channel].rxCount < sizeof(sp_Data[channel].rxBuffer))
		{
			// store the data
			sp_Data[channel].rxBuffer[sp_Data[channel].rxCount] = data;
			sp_Data[channel].rxCount++;
			// keep busy
		}
		else
		{
			// overflow
			sp_Data[channel].rxState = RX_STATE_OVERFLOW;
			ret = -1;
		}
		break;
	case	RX_STATE_READY:
		// should never happen
		ret = -1;
		break;
	case	RX_STATE_OVERFLOW:
		// ignore the data
		// keep overflow
		// count overflow
		if(sp_Data[channel].rxOverflowCount<0xff)
		{
			sp_Data[channel].rxOverflowCount++;
		}
		ret = -1;
		break;
	default:
		ret = -1;
		break;
	}

	return ret;
}

int serialportEvent_busIdleDetected_IRQ(SERIAL_PORT_CHANNEL channel)
{
	int ret = 0;

	switch( sp_Data[channel].rxState )
	{
	case RX_STATE_IDLE:
		// should never happens
		ret = -1;
		break;
	case RX_STATE_BUSY:
		// message finished
		sp_Data[channel].rxState = RX_STATE_READY;
		sp_Data[channel].rxLength = sp_Data[channel].rxCount;
		break;
	case RX_STATE_READY:
		// should never happens
		ret = -1;
		break;
	case RX_STATE_OVERFLOW:
		// directly back to idle
		sp_Data[channel].rxState = RX_STATE_IDLE;
		break;
	default:
		// directly back to idle
		sp_Data[channel].rxState = RX_STATE_IDLE;
		ret = -1;
		break;
	}

	return ret;
}

int serialport_receivePackage(SERIAL_PORT_CHANNEL channel, uint8 * pData, uint8 length)
{
	int ret = 0;

	if( sp_Data[channel].rxState==RX_STATE_READY )
	{
		// check buffer length
		if( sp_Data[channel].rxLength <= length )
		{
			uint8 i;
			// copy data
			for(i=0;i<sp_Data[channel].rxLength;i++) pData[i] = sp_Data[channel].rxBuffer[i];
			ret = i;
		}
		else
		{
			// user buffer not enough
			ret = -1;
		}

		// release rx buffer
		sp_Data[channel].rxState = RX_STATE_IDLE;
	}
	else
	{
		// no package received
		ret = 0;
	}

	return ret;
}
